Méthode d’exploration de données  
pour la prédiction du prix de maison  
présenté à  
Guy Wolf  
STT 3795  
Yi Xuan Luo  
Cheng Chen  
Weiyue Cai  
3
mai 2021  
1
Introduction  
Notre équipe analyse un ensemble des données de biens immobiliers disponible sur  
1
Kaggle et on s’intéresse aux prix des maisons et leur prédiction. Avec 79 variables ex-  
plicatives décrivant (presque) tous les aspects des maisons résidentielles à Ames, Iowa,  
cet ensemble des données nous permet de prédire les prix des maisons. Nous voulons  
étudier les facteurs qui influencent le prix de maison. En nous basant sur les résultats  
obtenus, nous allons choisir les modèles de prévision appropriés pour prédire les prix  
des maison à Ames.  
2
Compréhension des données  
Les données KaggleHousePrice comportent 1460 observations avec 80 attributs parmi  
lesquelles 37 attributs sont quantitatifs et 43 sont qualitatifs.  
Sans tenir compte des attributs, la moyenne du prix des maisons est 180921.195890. Le  
prix minimum est 34900, le maximum est 755000. La médiane est 163000, Q1 et Q3  
sont respectivement 129975 et 214000. La différence entre la moyenne et la médiane est  
grande, ce qui montre qu’il existe des valeurs aberrantes.  
1
2
3
Nettoyage des données  
Avant de visualiser les données pour déterminer la corrélation entre les variables et  
identifier les caractéristiques significatives, on doit nettoyer les données en premier afin  
d’obtenir un meilleur résultat.  
On a tout d’abord enlevé des observations aberrantes à l’aide des graphiques.  
Ensuite, on a traité les valeurs manquantes en appliquant les stratégies suivantes :  
(
(
1) remplacer les données manquantes par une valeur fixe  
2) pour les attributs qualitatifs, remplacer les données manquantes par 0, la moyenne  
ou la médiane.  
3) pour les attributs quantitatifs, remplacer les données manquantes en fonction de  
la description des données ou les remplacer par la valeur qui apparaît le plus souvent.  
Voir le code en annexe pour plus de détails).  
(
(
Finalement, on transforme certains attributs quantitatifs en attributs qualitatifs. Par  
exemple, pour la caractéristique YrSold, la graphique souligne les prix de maison en  
2
008, 2007, 2006, 2009 et 2010 sont pas mal constants.  
3
On transforme ainsi l’année de vente en une variable catégorielle. (On fait la même  
chose pour le mois de vente).  
Par contre, pour la graphique qui montre la corrélation entre le prix de maison et l’an-  
née de construction, on peut constater que le prix de maison a une tendance à monter  
avec l’année de construction. Autrement dit, plus la maison est neuve, plus possible son  
prix est haut. Alors, on le laisse comme ça.  
4
Visualisation des données  
4
.1 Analyse de la Variance (ANOVA)  
Comme nous disposons des variables catégorielles, on va utiliser l’Analyse de la Va-  
riance (ANOVA) comme la méthode statistique pour sélectionner les variables qui ont  
un impact significatif sur le prix.  
L’approche de l’ANOVA consiste à effectuer un test F pour vérifier s’il existe une va-  
riance entre les groupes (i.e. les différentes variables catégorielles) en comparant la  
4
variance entre les groupes et la variance au sein des groupes 2.  
On peut calculer la somme des carrés entre les groupes (SSB) avec son degré de liberté  
(
(
dfb) et la somme des carrés au sein des groupes(SSW) avec le degré de liberté associée  
dfw). Puisqu’on veut comparer la variance entre les groupes et la variance au sein des  
groupes, on peut calculer la statistique F =  
SSB/dfb  
SSW/dfw  
.
Ensuit, on va utiliser la statistique F, la loi de Fisher, pour tester l’hypothèse nulle  
H0 : la variance est identique pour les différents groupes. Si la valeur-p est inférieure  
au seuil, mettons 0,005, alors on rejette H0.  
On observe qu’il y a pas mal de variables qui ont une valeur-p beaucoup plus inférieure  
à 0,005, p.e., la variable neightberood a 2.151365e-225 comme la valeur-p.  
Cinq variables, Street, LandSlope, MoSold, Utilities, YrSold, ne sont pas significatives.  
Nous enlevons donc ces variables non significatives.  
5
Avec l’utilisation de ANOVA, la graphique suivante montre une estimation de l’influence  
des attributs qualitatifs sur le prix de maison. La location de maison (neighborhood),  
la qualité de matériel de construction de maison à l’extérieur (ExterQual) et la qualité  
de sous-sol (BsmtQual) sont trois facteurs qualitatifs ayant plus de impact sur le prix  
de maison.  
4
.2 Heatmap  
Nous avons déjà analysé l’influence des attributs qualitatifs sur le prix. Pour connaître  
la corrélation entre les attributs quantitatifs et le prix de la maison, on utilise HeatMap  
afin de visualiser le coefficient de la corrélation entre deux variables.  
Le tableau ci-dessous affichent les 24 attributs quantitatifs ayant une corrélation plus  
grande avec le prix de vente :  
6
Les attributs OverallQual, GrlivArea, TotalBsmtSF, GarageCar ont plus d’influence sur  
le prix d’une maison par rapport aux autres attributs. Ils ont tous une corrélation po-  
sitive sur le prix.  
4
.3 Réduction des dimensions  
Comme ce qu’on a déjà vu en classe, la méthode de la réduction des dimensions, entres  
autres l’analyse en composantes principales (PCA), la notion de variété (manifold)  
comme Isomap, MDS, TSNE et l’approche de partitionnement de données (cluster)  
telle que K-means sont des outils utiles et appropriés pour visualiser des données avec  
plusieurs attributs.  
7
Voici une illustration de cluster des données de notre projet :  
5
Pré-traitement des données  
Après avoir visualisé les données, on s’intéresse maintenant au pré-traitement des don-  
nées. On a corrigé en premier les valeurs avec une distribution asymétrique au moyen  
de la normalisation des certaines variables quantitatives avec la transformation log1p  
implémentée dans python. Par la suite, on entame le processus de feature engineering  
en créant de nouvelles variables. Par exemple, pour prédire le prix de maison, on rajoute  
les caractéristiques suivantes pour améliorer la performace des modèles de prédiction :  
isHouseOld, isRemodel, hasPool, has2ndfloor, hasGarage et hasBasement (Voir le code  
en annexe pour plus de détails).  
6
Modèles de prédiction  
Cette partie porte sur l’analyse des modèles de prédiction utilisés pour prédire le prix  
de maison. On va parler principalement de quatre méthodes : la régression bayésienne  
(
plus précisément, bayesian ridge regression), la machine à vecteurs de support pour la  
régression, l’arbre de décision pour la régression et la forêt aléatoire pour la régression.  
8
6
.1 Régression bayésienne (Bayesian Ridge Regression)  
Avant de parler de la bayesian ridge regression, on va d’abord se rappeler la régres-  
sion linéaire. La régression linéaire ajuste un modèle linéaire avec des coefficients w =  
(
w , w , ..., w ) afin de minimiser la somme résiduelle des carrés entre les cibles observées  
1 2 p  
3
dans l’ensemble de données (y) et les cibles prédites par l’approximation linéaire (Xw) .  
Mathématiquement, il résout un problème de la forme :  
2
min ||Xw y||2  
w
6
.1.1 Ridge Regression  
La ridge regression résout certains des problèmes des moindres carrés ordinaires en  
imposant une pénalité sur les coefficients. Les ridge coefficients minimisent la somme  
2
2
résiduelle des carrés et α||w|| :  
2
2
2
2
min ||Xw  y|| + α||w||  
w
Le paramètre de complexité α  0 contrôle la quantité de rétrécissement : plus la  
valeur de α est grande, plus le rétrécissement est important, ce qui implique que plus  
les coefficients sont robustes à la colinéarité.  
(
Source : scikit-learn 1.1.2.1. Regression 4)  
3
9
6
.1.2 Bayesian Ridge Regression  
La régression linéaire consiste à appliquer la méthode de l’inférence bayésienne dans la  
régression linéaire. Lorsque le modèle de régression a des erreurs qui ont une distribu-  
tion normale, et si on suppose une forme particulière de distribution de la probabilité  
antérieure, alors on peut essayer d’obtenir la distribution de probabilité postérieure des  
paramètres du modèle.  
5
On suppose que la sortie y est distribuée de manière gaussienne autour de Xw :  
p(y|X, w, α) = N(y|Xw, α)  
 α est considéré comme une variable aléatoire.  
Pour la bayesian ridge regression, la probabilité antérieure du coefficient w est donnée  
par une gaussienne sphérique :  
1
p(w|λ) = N(w|0, λ I )  
p
 α et λ suivent la Loi Gamma.  
Les paramètres w, α et λ sont estimés conjointement pendant l’entraînement du modèle.  
Les paramètres de régularisation α et λ sont estimés en maximisant la vraisemblance  
marginale logarithmique. 6  
La régression bayésienne permet d’éviter le problème de sur-ajustement (over-fitting) du  
maximum de vraisemblance, ce qui fait que cette approche s’adapte bien aux données.  
Voici une illustration de la distribution de la prédiction pour les modèles de régression  
7
linéaire bayésienne. .  
5
6
7
. Bishop, Christopher. Pattern Recognition and Machine Learning, p.157  
1
0
Les modèles de la ridge regression et la bayesian ridge regression fonctionnent très bien  
sur les données du projet, ce qui pourrait être expliqué par le fait qu’on a pré-traité les  
données asymétriques en appliquant log1p avant d’entraîner les modèles de prédiction.  
Puisque la distribution de la probabilité antérieure et celle de la probabilité postérieure  
sont supposées de suivre la loi normale, les modèles de la régression Ridge et la bayesian  
ridge regression s’adaptent bien aux données standardisées.  
6
.2 SVM pour la régression (Support Vector Regression)  
Nous avons déjà vu en classe la machine à vecteurs de support pour les problèmes de  
classification. La machine à vecteurs de support peut aussi résoudre les problèmes de  
régression, support vector regression (SVR).  
SVR utilise presque les mêmes principes (la minimisation des erreurs et la maximisa-  
tion de la marge) que SVM, mais avec quelques différences mineures. Supposons que  
l’équation de l’hyper plan est wx + b = 0,  
les deux équations des frontières de décision sont :  
wx + b = ꢀ, wx + b = ꢀ  
L’objectif est de maximiser le nombre des points dans les frontières.  
1
1
(
Source : Medium 8)  
On a les fonctions objectives pour SVR 9,  
N
X
1
2
(ξ + ξ )  
i
i
min ||w|| + C  
2
i=1  
s.t.y  (wx + b)   + ξ  
i
i
i
(
wx + b)  y   + ξ  
i
i
i
ξ  0  
i
ξ  0  
i
La constante C est le paramètre de contrainte, une valeur positive qui contrôle la pé-  
nalité imposée aux points qui se situent en dehors de la marge , et permet d’éviter le  
sur-ajustement afin de garantir la régularisation.  
Le guide 10 d’utilisateur de scikit-learn nous propose quelques suggestions utiles lors  
d’appliquer l’algorithme de SVR :  
1
. Réglage d’hyperparamètres sur C (Hyperparameter Tuning) : C est égal à 1 par dé-  
faut. S’il y a beaucoup de bruit dans les données, on devrait diminuer la constante C,  
ce qui correspond à plus de régularisation.  
2
. Il est fortement recommandé de standardiser les données. Par exemple, nous pou-  
vons standardiser les données X dans [0, 1] ou [1, 1] ou les normaliser pour que X ait  
une moyenne de 0 et une variance de 1. Il faut faire le même pré-traitement sur les  
données de test. Ce genre de pré-traitement peut être implémenté avec l’utilisation de  
8
1
1
2
sklearn.pipeline.  
(
Source : Le guide d’utilisateur de scikit-learn)  
Ces deux suggestions sont importantes quand on applique l’algorithme de SVR dans la  
pratique. Avant de faire le réglage d’hyperparamètres sur C et la standardisation des  
données, on a obtenu 0.27807 comme erreur sur les données d’entraînement.  
Après le réglage sur le modèle et le pré-traitement (RobustScaler) sur les données,  
l’erreur a été beaucoup réduite (à 0.11).  
6
.3 Arbre de décision pour la régression (Decision Tree Regres-  
sion)  
L’arbre de décision est une méthode de base de classification et de régression. Chaque  
arbre est composé de nœuds et d’arêtes orientées. Il existe deux types de nœuds : les  
nœuds internes et les nœuds externes (feuilles). La feuille représente une catégorie ou  
une valeur de la variable-cible. Le nœud interne correspond à des combinaisons de va-  
riables d’entrée qui mènent aux valeurs de feuilles.  
En fait, l’arbre de décision consiste en une méthode de division de l’espace avec des  
hyperplans. Chaque fois qu’on produit des noeuds enfants, l’espace actuel (l’ensemble  
des données) est divisé en fonction de la valeur de sorte que chaque feuille corresponde  
à une partie distincte de l’espace.  
1
3
6
.3.1 Construction d’un arbre de décision par CART  
L’approche par arbre de décision commence à partir du nœud racine, teste une certaine  
caractéristique de l’échantillon et divise l’arbre du noeud-partent vers ses enfants en  
sélectionnant à chaque étape une variable d’entrée qui réalise la meilleure séparation de  
l’ensemble des données. De cette manière, les échantillons sont testés et distribués de  
manière récursive jusqu’à ce que la feuille soit atteinte.  
Dans le cas de l’arbre de régression, la valeur de sortie est continue et donc on utilise  
la minimisation de la somme des carrés de l’erreur pour obtenir la valeur de sortie op-  
timale. Elle utilise la moyenne des feuilles comme la prédiction de la catégorie.  
On va expliquer plus précisément la construction de l’arbre pour la régression. Soit D,  
un ensemble de donnée D = {(x , y ), (x , y ), ..., (x , y )}, supposons qu’on veut diviser  
1
1
2
2
n
n
X en m parties R , R , ...R , la valeur de sortie c = average(y |x  R ). On choisit  
1
2
m
m
i
i
m
j
la j-ième variable x et sa valeur s comme la variable de coupure (splitting variable) et  
k
le point de coupure (splitting point). On définit deux régions R (k, s) = {x|x  s} et  
1
l
j
R (l, s) = {x|x > s} pour représenter le sous-arbre gauche et le sous-arbre droit du x .  
2
Afin de trouver la variable de coupure optimale, on résout la fonction objective 11  
:
X
X
2
2
min[min  
(y  c ) + min  
(y  c ) ]  
i
1
i
2
j,s  
c1  
c2  
xiR1  
xiR2  
où les c , c optimaux sont cˆ = average(y |x  R ) et cˆ = average(y |x  R ).  
1
2
1
i
i
1
2
i
i
2
L’algorithme parcourt toutes les variables et trouve la variable de coupure optimale j.  
Ensuite, on répète le processus de division ci-dessus jusqu’à ce que la condition d’arrêt  
1
1. Hang LI, Statistical Learning Methods, p.68  
1
4
soit remplie. De cette manière, un arbre de régression est généré.  
Afin d’éviter le problème de sur-ajustement, scikit-learn utilise l’algorithme de minimal  
cost-complexity pruning pour faire l’élagage de l’arbre.  
6
.3.2 Avantages et Faiblesses  
L’arbre de décision présente certains avantages :  
(
(
1) La vitesse d’entraînement de prédiction est rapide.  
2) Il est facile de comprendre les relations non-linéaires entre les caractéristiques des  
données.  
(
(
3) Les résultats sont faciles à interpréter.  
4) Il est facile de trouver les caractéristiques les plus importantes de l’ensemble de  
données.  
Par contre, cette méthode présente aussi certaines faiblesses :  
(
(
(
(
1) La précision de la prédiction est faible.  
2) Cette approche ne convient pas parfaitement aux petits ensembles de données.  
3) L’algorithme est facile d’être influencée par le bruit des données.  
4) Lorsque de nouvelles données sont ajoutées, il n’est pas facile de mettre à jour le  
modèle.  
1
2
Le guide d’utilisateur de scikit  learn nous propose également quelques suggestions  
utiles lors d’appliquer l’algorithme de l’arbre de décision :  
(
1) L’algorithme de l’arbre de décision a tendance à sur-ajuster à l’ensemble des don-  
nées qui ont beaucoup de caractéristiques (features). Il est important de bien calculer  
le rapport entre le nombre d’échantillons et le nombre de caractéristiques, parce que  
l’arbre avec peu d’échantillons dans un espace multidimensionnel a tendance à être sur-  
ajusté.  
(
2) On peut procéder à la réduction des dimensions (PCA ou feature selection par  
exemple) à l’avance pour bien identifier les caractéristiques significatives.  
3) Il nous faut aussi régler les paramètres de l’arbre comme max depth, min samples  
(
split et min samples leaf pour s’assurer que des échantillons multiples informent chaque  
décision dans l’arbre en contrôlant les divisions qui seront prises en compte.  
Si on fait le lien avec l’ensemble des données de notre projet, on a obtenu 0.2017 comme  
l’erreur. Même si nous avons bien pré-traité nos données et ajusté les paramètres, le  
résultat n’est pas satisfaisant (0.1808),  
1
1
5
ce qui s’explique probablement par les raisons suivantes :  
(
(
(
1) la mauvaise prédiction de l’arbre de décision  
2) le sur-ajustement causé par les observations aberrantes.  
3) le nombre des caractéristiques est grand, ce qui implique que l’algorithme de l’arbre  
de décision a tendance à mal indiquer les caractéristiques significatives. On pourrait  
appliquer PCA sur les données avant d’entraîner le modèle de prédiction.  
6
.4 Forêt aléatoire pour la régression (Random Forest Regres-  
sion)  
L’algorithme de la forêt aléatoire appartient à la méthode d’apprentissage d’ensemble.  
Dans une forêt aléatoire, chaque arbre de l’ensemble est construit au moyen des tech-  
niques de Bootstrap sur la base des échantillons avec remplacement de l’ensemble des  
données. Les techniques de Bootstrap font référence aux méthodes d’inférence statis-  
tique basées sur l’échantillonnage aléatoire avec remplacement. Il nous permet de mieux  
comprendre le biais et la variance du jeu de données.  
En outre, lors de la division de chaque nœud pendant la construction d’un arbre, la  
meilleure division est trouvée soit (1) à partir de toutes les caractéristiques, soit (2)  
à partir d’un sous-ensemble aléatoire de taille de max features. Ces deux sources aléa-  
toires ont pour but de diminuer la variance de l’estimateur de la forêt et d’éviter le  
sur-ajustement causé pour un seul arbre. 13  
Au stade de la prédiction, certaines erreurs peuvent être éliminées en prenant la moyenne  
de ces estimations. Les forêts aléatoires parviennent à réduire la variance en combinant  
différents arbres, mais parfois le biais est légèrement croissant. En pratique, la réduction  
de la variance est généralement significative, ce qui se traduit par un meilleur modèle  
global.  
1
6
Lors d’appliquer l’algorithme de la forêt aléatoire pour la régression sur l’ensemble  
des données, on peut utiliser la fonction RandomForestRegressor pré-implémentée dans  
scikit-learn 14  
:
1) Le paramètre n_estimators sert à générer 100 arbres de décision par défaut. Nor-  
(
malement, plus le nombre des arbres est grand, plus le résultat de prédiction est précis.  
Cependant, ceci prend plus de temps et le résultat va se converger si le nombre de  
l’arbre est trop grand.  
(
2) La fonction criterion permet de mesurer la qualité d’un fractionnement. Par exemple,  
si on choisit "MSE" comme critère, l’erreur quadratique moyenne entre le nœud parent  
et le nœud enfant est choisie comme la critère de la sélection des caractéristiques.  
2
(
3) L’interface score retourne R , le coefficient de détermination de la prédiction. On  
peut définir R comme suit :  
u
v
2
R = 1 −  
N
X
2
( yˆ  y )  
i i  
u =  
v =  
i=1  
N
X
2
(y  y)  
i
i=1  
où N est le nombre des échantillons, yˆ est la valeur de prédiction, et y est la moyenne  
i
1
7
u
v
des valeurs observées. La valeur de u va être petite si y est proche de yˆ . Le tend vers  
donc zéro, ce qui fait que la valeur de R est proche de 1.  
i
i
2
On peut également personnaliser la métrique pour évaluer les erreurs du modèle de  
prédiction. Dans notre project, on a choisi la racine de l’erreur quadratique moyenne  
(
RMSE) entre le logarithme de la valeur prédite et le logarithme du prix de vente ob-  
servé. En ce qui concerne la prédiction obtenue par le modèle de la forêt aléatoire,  
nous avons obtenu un résultat relativement satisfaisant même sans régler les hyperpa-  
ramètres. (Veuillez voir le code en annexe pour plus d’informations).  
C’est probablement grâce à des raisons suivantes : l’algorithme de la forêt aléatoire peut  
traiter des données avec une haute dimensionnalité parce qu’elle génère les arbres de  
décision à partie de la méthode statistique Bootstrap qui peut re-échantillonner à partir  
de l’ensemble de donnée. La prédiction est supportée par l’analyse de la robustesse.  
7
Conclusion  
Nous avons expliqué précisément quatre méthodes de prédiction vues en classe dans la  
dernière partie. À part de ces quatre algorithmes mentionnées ci-dessus, nous avons éga-  
lement utilisé les modèles pour la régression suivantes : Lasso Regression, Extra Trees,  
Gradient boosting, LGBM Regressor et XGBoost Regressor.  
Voici la moyenne et l’écart-type de RMSE des modèles de prédiction (without hyperpa-  
rameter tuning).  
Nous avons procédé au réglage d’hyperparamètres pour certains modèles à l’aide des  
méthodes de cross validation et grid search. Voici la moyenne et l’écart-type de RMSE  
de certains modèles de prédiction (with hyperparameter tuning).  
1
8
Nous avons décidé de choisir deux stratégies de blending ci-dessous pour calculer la  
prédiction finale :  
Les résultats de prédiction sont évalués sur la base de l’erreur quadratique moyenne  
(
RMSE) entre le logarithme de la valeur prédite et le logarithme du prix de vente ob-  
servé. (Prendre les logarithmes signifie que les erreurs de prédiction des maisons chères  
et des maisons bon marché affecteront le résultat de la même manière). Nous avons  
obtenu 0.12255 et 0.12332 comme résultats pour la première stratégie et la deuxième  
stratégie respectivement, ce qui montre qu’on a obtenu un résultat relativement réussi  
(
top 13% parmi tous les résultats de prédiction sur Kaggle).  
Il existe plusieurs façons d’améliorer nos résultats et de rendre le modèle de prédiction  
plus performant.  
Au niveau du pré-traitement des données, nous pouvons mettre au point les stratégies  
plus gagnantes pour imputer les valeurs manquantes :  
(
1) Remplacer les valeurs manquantes en fonction de la corrélation entre la caractéris-  
tique et le prix ou la corrélation entre les attributs au lieu de les remplacer simplement  
par 0, la moyenne ou la médiane.  
(
2) Utiliser la fonction KNNImputer implémentée dans python pour compléter les va-  
leurs manquantes à l’aide de l’approche k Nearest Neighbors.  
3) Normaliser les données asymétriques avec la transformation de boxcox1p ou boxcox  
normmax et comparer les résultats avec ceux de log1p.  
4) Créer plus de variables pertinentes durant le processus de feature engineering et  
(
(
appliquer PCA si nécessaire.  
Au niveau de l’entraînement des modèles de prédiction et de hyperparameter tuning,  
(
1) Faire un nombre beaucoup plus important d’essais pour trouver les valeurs de pa-  
ramètres optimales.  
2) Essayer les autres méthodes performantes telles que Stacked Regressor et Cat Boost  
(
1
9
Regressor.  
3) Utiliser la fonction get_feature_importance pour la sélection des caractéristiques,  
(
ce qui nous permet de mieux comprendre le fonctionnement de l’algorithme et de sa-  
voir quelles caractéristiques que l’algorithme utilise le plus pour arriver à la prédiction  
finale.  
(
4) Avec la conclusion de la sélection des caractéristiques, on peut faire encore une fois  
l’optimisation des hyperparamètres.  
Contributions des membres de l’équipe :  
Yi Xuan Luo : Introduction, Compréhension des données, Nettoyage des données et  
Conclusion.  
Cheng Chen : ANOVA, Heatmap, Arbre de décision pour la régression et Forêt aléatoire  
pour la régression.  
Weiyue Cai : Réduction des dimensions, Pré-traitement des données, Bayesian Ridge  
Regression et SVM pour la régression.  
8
Références  
Références  
[
[
[
[
4] Bishop, Christopher M. Pattern Recognition and Machine Learning. New York :  
Springer, 2006. p.157  
[
[
[
[
7] Hang Li. Statistical Learning Methods, Second Edition. Tsinghua University Press,  
2
019  
8] Hang Li. Statistical Learning Methods, Second Edition. Tsinghua University Press,  
019  
2
2
0
STT3795 - Projet final  
Yi Xuan Luo  
Cheng Chen  
Weiyue Cai  
Compréhension des données  
In [1]:  
import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
import seaborn as sns  
from scipy.stats import skew, norm  
import scipy.stats as stats  
import warnings  
warnings.filterwarnings('ignore')  
In [2]:  
from google.colab import files  
upload_train = files.upload()  
Choose Files No file chosen  
Upload widget is only available when the cell has been executed in the current browser session. Please rerun  
this cell to enable.  
Saving train.csv to train.csv  
In [3]:  
from google.colab import files  
uploaded_test = files.upload()  
Choose Files No file chosen  
Upload widget is only available when the cell has been executed in the current browser session. Please rerun  
this cell to enable.  
Saving test.csv to test.csv  
In [4]:  
import pandas as pd  
import io  
train = pd.read_csv(io.BytesIO(upload_train['train.csv']), index_col=None)  
train.shape  
(
1460, 81)  
Out[4]:  
In [5]:  
test = pd.read_csv(io.BytesIO(uploaded_test['test.csv']), index_col=None)  
test.shape  
(
1459, 80)  
Out[5]:  
In [6]:  
train.columns  
Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street',  
Out[6]:  
'
'
'
'
'
'
'
'
'
'
'
'
'
Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig',  
LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType',  
HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd',  
RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType',  
MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual',  
BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1',  
BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating',  
HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF',  
LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath',  
HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual',  
TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType',  
GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual',  
GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF',  
'
'
'
EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC',  
Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType',  
SaleCondition', 'SalePrice'],  
dtype='object')  
In [7]:  
Out[7]:  
#
numerical attributes  
num_cols = train.columns[train.dtypes != 'object']  
num_cols  
Index(['Id', 'MSSubClass', 'LotFrontage', 'LotArea', 'OverallQual',  
'
'
'
'
'
'
'
OverallCond', 'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1',  
BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF',  
LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath',  
HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd',  
Fireplaces', 'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF',  
OpenPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea',  
MiscVal', 'MoSold', 'YrSold', 'SalePrice'],  
dtype='object')  
In [8]:  
Out[8]:  
#
categorical attributes  
cat_cols = train.columns[train.dtypes == 'object']  
cat_cols  
Index(['MSZoning', 'Street', 'Alley', 'LotShape', 'LandContour', 'Utilities',  
'
'
'
'
'
'
'
'
LotConfig', 'LandSlope', 'Neighborhood', 'Condition1', 'Condition2',  
BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl', 'Exterior1st',  
Exterior2nd', 'MasVnrType', 'ExterQual', 'ExterCond', 'Foundation',  
BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2',  
Heating', 'HeatingQC', 'CentralAir', 'Electrical', 'KitchenQual',  
Functional', 'FireplaceQu', 'GarageType', 'GarageFinish', 'GarageQual',  
GarageCond', 'PavedDrive', 'PoolQC', 'Fence', 'MiscFeature',  
SaleType', 'SaleCondition'],  
dtype='object')  
Nettoyage des données  
In [9]: # visualization the relation of some numerical attributes with sale price  
in order to remove the outliers in the traning data  
#
plt.figure(figsize = (10,5))  
sns.regplot(data = train, x = 'LotFrontage', y='SalePrice')  
plt.title('LotFrontage~SalePrice', fontsize = 12)  
plt.show()  
In [10]:  
Out[10]:  
train.sort_values(by = 'LotFrontage', ascending = False)[:2]  
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Conditio  
1
298 1299  
34 935  
60  
20  
RL  
RL  
313.0  
313.0  
63887  
27650  
Pave NaN  
Pave NaN  
IR3  
IR2  
Bnk  
HLS  
AllPub  
AllPub  
Corner  
Inside  
Gtl  
Edwards  
NAmes  
Fee  
Po  
9
Mod  
2
rows × 81 columns  
In [11]:  
In [12]:  
train = train.drop(train[train['Id'] == 1299].index)  
train = train.drop(train[train['Id'] == 935].index)  
plt.figure(figsize = (10,5))  
sns.regplot(data = train, x = 'GrLivArea', y='SalePrice')  
plt.title('GrLivArea~SalePrice', fontsize = 12)  
plt.show()  
In [13]:  
train.sort_values(by = 'GrLivArea', ascending = False)[:1]  
Out[13]:  
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Condition1  
23 524 60 RL 130.0 40094 Pave NaN IR1 Bnk AllPub Inside Gtl Edwards PosN  
5
1
rows × 81 columns  
In [14]:  
In [15]:  
train = train.drop(train[train['Id'] == 524].index)  
plt.figure(figsize = (10,5))  
sns.regplot(data = train, x = 'LotArea', y='SalePrice')  
plt.title('LotArea~SalePrice', fontsize = 12)  
plt.show()  
In [16]:  
Out[16]:  
train.sort_values(by = 'LotArea', ascending = False)[:3]  
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Condition1  
3
3
2
13 314  
35 336  
49 250  
20  
190  
50  
RL  
RL  
RL  
150.0  
NaN  
NaN  
215245  
164660  
159000  
Pave NaN  
Grvl NaN  
Pave NaN  
IR3  
IR1  
IR2  
Low  
HLS  
Low  
AllPub  
AllPub  
AllPub  
Inside  
Corner  
Sev  
Sev  
Sev  
Timber  
Timber  
ClearCr  
Norm  
Norm  
Norm  
CulDSac  
3
rows × 81 columns  
In [17]:  
train = train.drop(train[train['Id'] == 314].index)  
train = train.drop(train[train['Id'] == 336].index)  
train = train.drop(train[train['Id'] == 250].index)  
In [18]:  
train.reset_index(drop=True, inplace=True)  
Traiter les valeurs manquantes  
In [19]:  
In [20]:  
#
Split features and labels  
X_train = train.drop(['SalePrice'], axis=1, inplace=False)  
y_train = train['SalePrice'].reset_index(drop=True)  
#
concatenate training and test datasets  
all_data = pd.concat([X_train, test]).reset_index(drop=True)  
all_data.shape  
(
2913, 80)  
Out[20]:  
In [21]:  
#
check if there are duplicated values  
all_data.duplicated().sum()  
0
Out[21]:  
In [22]:  
#
check if there are missing values  
total_missing_data = all_data.isnull().sum().sort_values(ascending=False)  
percent = (all_data.isnull().sum()/all_data.isnull().count()).sort_values(ascending=False)  
missing_data = pd.concat([total_missing_data, percent], axis=1, keys=['Total', 'Percent'])  
missing_data = missing_data[missing_data['Total'] != 0]  
missing_data  
Out[22]:  
Total Percent  
PoolQC 2904 0.996910  
MiscFeature 2810 0.964641  
Alley 2715 0.932029  
Fence 2342 0.803982  
FireplaceQu 1420 0.487470  
LotFrontage  
GarageCond  
GarageQual  
GarageYrBlt  
GarageFinish  
GarageType  
BsmtCond  
484 0.166152  
159 0.054583  
159 0.054583  
159 0.054583  
159 0.054583  
157 0.053896  
82 0.028150  
82 0.028150  
81 0.027806  
80 0.027463  
79 0.027120  
24 0.008239  
23 0.007896  
4 0.001373  
BsmtExposure  
BsmtQual  
BsmtFinType2  
BsmtFinType1  
MasVnrType  
MasVnrArea  
MSZoning  
BsmtHalfBath  
2 0.000687  
Total Percent  
2 0.000687  
2 0.000687  
2 0.000687  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
1 0.000343  
Utilities  
Functional  
BsmtFullBath  
BsmtFinSF1  
Exterior1st  
Exterior2nd  
BsmtFinSF2  
BsmtUnfSF  
TotalBsmtSF  
SaleType  
Electrical  
KitchenQual  
GarageArea  
GarageCars  
In [23]:  
In [24]:  
backup = missing_data.reset_index(inplace=False)  
memo_cat = []  
memo_num = []  
missing_col = backup['index'].tolist()  
print(missing_col)  
[
'PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu', 'LotFrontage', 'GarageCond', 'GarageQual', 'GarageYrBlt', 'GarageFinish',  
'
GarageType', 'BsmtCond', 'BsmtExposure', 'BsmtQual', 'BsmtFinType2', 'BsmtFinType1', 'MasVnrType', 'MasVnrArea', 'MSZoning', 'BsmtH  
alfBath', 'Utilities', 'Functional', 'BsmtFullBath', 'BsmtFinSF1', 'Exterior1st', 'Exterior2nd', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBs  
mtSF', 'SaleType', 'Electrical', 'KitchenQual', 'GarageArea', 'GarageCars']  
In [25]:  
missing_col = backup['index'].tolist()  
for i in range(len(missing_col)):  
if missing_col[i] in cat_cols:  
memo_cat.append(missing_col[i])  
elif missing_col[i] in num_cols:  
memo_num.append(missing_col[i])  
print(memo_cat)  
print(memo_num)  
[
'PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu', 'GarageCond', 'GarageQual', 'GarageFinish', 'GarageType', 'BsmtCond', 'Bs  
mtExposure', 'BsmtQual', 'BsmtFinType2', 'BsmtFinType1', 'MasVnrType', 'MSZoning', 'Utilities', 'Functional', 'Exterior1st', 'Exteri  
or2nd', 'SaleType', 'Electrical', 'KitchenQual']  
[
'
'LotFrontage', 'GarageYrBlt', 'MasVnrArea', 'BsmtHalfBath', 'BsmtFullBath', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF',  
GarageArea', 'GarageCars']  
missing categorical columns: ['PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu', 'GarageCond', 'GarageQual', 'GarageFinish', 'GarageType',  
'
'
BsmtCond', 'BsmtExposure', 'BsmtQual', 'BsmtFinType2', 'BsmtFinType1', 'MasVnrType', 'MSZoning', 'Utilities', 'Functional', 'Exterior1st', 'Exterior2nd',  
SaleType', 'Electrical', 'KitchenQual']  
missing numerical columns: ['LotFrontage', 'GarageYrBlt', 'MasVnrArea', 'BsmtHalfBath', 'BsmtFullBath', 'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF',  
'TotalBsmtSF', 'GarageArea', 'GarageCars']  
In [26]:  
mean_GarageYrBlt = all_data['GarageYrBlt'].mean()  
np.floor(mean_GarageYrBlt)  
1
978.0  
Out[26]:  
In [27]:  
cols2 = ["MSZoning", "BsmtFullBath", "BsmtHalfBath", "Utilities", "SaleType","Exterior1st", "Exterior2nd"]  
for col in cols2:  
all_data[col] = all_data[col].fillna(all_data[col].mode()[0])  
#
replace nan in the LotFrontage by the median  
all_data['LotFrontage']=all_data.groupby(['Neighborhood'])['LotFrontage'].transform(lambda x: x.fillna(x.median()))  
#
replace nan in the following columns according to the data description  
all_data['Functional'] = all_data['Functional'].fillna('Typ')  
all_data['Electrical'] = all_data['Electrical'].fillna("SBrkr")  
all_data['KitchenQual'] = all_data['KitchenQual'].fillna("TA")  
#
replace nan by mean  
all_data['GarageYrBlt'] = all_data['GarageYrBlt'].fillna(1978)  
In [28]:  
#
replace missing data with None  
gr1 = memo_cat  
for col in gr1:  
all_data[col] = all_data[col].fillna('None')  
#
replace missing data with 0  
gr2 = memo_num  
for col in gr2:  
all_data[col] = all_data[col].fillna(0)  
In [29]:  
Out[29]:  
total_missing_data = all_data.isnull().sum().sort_values(ascending=False)  
total_missing_data  
SaleCondition  
SaleType  
RoofStyle  
RoofMatl  
0
0
0
0
0
.
0
0
0
Exterior1st  
.
TotRmsAbvGrd  
Functional  
Fireplaces  
FireplaceQu  
Id  
0
0
Length: 80, dtype: int64  
In [30]:  
Out[30]:  
all_data  
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Conditio  
0
1
2
3
4
1
2
3
4
5
...  
60  
20  
RL  
RL  
RL  
RL  
RL  
...  
65.0  
80.0  
68.0  
60.0  
84.0  
...  
8450  
9600  
11250  
9550  
14260  
...  
Pave None  
Pave None  
Pave None  
Pave None  
Pave None  
Reg  
Reg  
IR1  
IR1  
IR1  
...  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
...  
AllPub  
AllPub  
AllPub  
AllPub  
AllPub  
...  
Inside  
FR2  
Gtl  
Gtl  
Gtl  
Gtl  
Gtl  
...  
CollgCr  
Veenker  
CollgCr  
Crawfor  
NoRidge  
...  
No  
Fee  
No  
No  
No  
60  
Inside  
Corner  
FR2  
70  
60  
.
..  
...  
...  
...  
...  
2
2
2
2
2
908 2915  
909 2916  
910 2917  
911 2918  
912 2919  
160  
160  
20  
RM  
RM  
RL  
RL  
RL  
21.0  
21.0  
160.0  
62.0  
74.0  
1936  
1894  
20000  
10441  
9627  
Pave None  
Pave None  
Pave None  
Pave None  
Pave None  
Reg  
Reg  
Reg  
Reg  
Reg  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
AllPub  
AllPub  
AllPub  
AllPub  
AllPub  
Inside  
Inside  
Inside  
Inside  
Inside  
Gtl  
Gtl  
Gtl  
Gtl  
Mod  
MeadowV  
MeadowV  
Mitchel  
Mitchel  
Mitchel  
No  
No  
No  
No  
No  
85  
60  
2
913 rows × 80 columns  
Visualisation des données  
In [31]:  
#
convert the type of MSSubClass into categorical characteristic  
all_data['MSSubClass'] = all_data['MSSubClass'].astype(str)  
In [32]:  
In [33]:  
#
split traning data features from all_data  
copy1 = all_data.copy()  
training_features = copy1[:len(y_train)]  
training_features.shape  
(
1454, 80)  
Out[33]:  
In [34]:  
#
check if year built correlates to the sale price  
year_vs_price = pd.concat([y_train, training_features['YearBuilt']], axis=1)  
plt.figure(figsize = (25, 8))  
sns.regplot(data=year_vs_price, x=training_features['YearBuilt'], y="SalePrice")  
plt.xticks(rotation=45);  
In [35]:  
#
check if year sold correlates to the sale price  
yearsold_vs_price = pd.concat([y_train, training_features['YrSold']], axis=1)  
f, ax = plt.subplots(figsize=(25, 8))  
fig = sns.boxplot(x=training_features['YrSold'], y="SalePrice", data=yearsold_vs_price )  
fig.axis(ymin=0, ymax=800000);  
plt.xticks(rotation=45);  
In [36]:  
In [37]:  
all_data['YrSold'] = all_data['YrSold'].apply(str)  
#
check if month sold correlates to the sale price  
monthsold_vs_price = pd.concat([y_train, training_features['MoSold']], axis=1)  
f, ax = plt.subplots(figsize=(25, 8))  
fig = sns.boxplot(x=training_features['MoSold'], y="SalePrice", data=monthsold_vs_price)  
fig.axis(ymin=0, ymax=800000);  
plt.xticks(rotation=45);  
In [38]:  
In [39]:  
all_data['MoSold'] = all_data['MoSold'].apply(str)  
num_cols_update = all_data.columns[all_data.dtypes != 'object']  
cat_cols_update = all_data.columns[all_data.dtypes == 'object']  
Analyse de la Variance (ANOVA)  
Using ANOVA for categorical feature selection:  
In [40]:  
In [41]:  
y_train_df = pd.DataFrame(data = y_train, copy=True)  
train_copy = pd.concat([y_train_df, training_features], axis=1)  
In [43]:  
Out[43]:  
train_copy.head()  
SalePrice Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Con  
0
1
2
3
4
208500  
181500  
223500  
140000  
250000  
1
2
3
4
5
60  
20  
60  
70  
60  
RL  
RL  
RL  
RL  
RL  
65.0  
80.0  
68.0  
60.0  
84.0  
8450  
9600  
Pave None  
Pave None  
Pave None  
Pave None  
Pave None  
Reg  
Reg  
IR1  
IR1  
IR1  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
AllPub  
AllPub  
AllPub  
AllPub  
AllPub  
Inside  
FR2  
Gtl  
Gtl  
Gtl  
Gtl  
Gtl  
CollgCr  
Veenker  
CollgCr  
11250  
9550  
Inside  
Corner  
FR2  
Crawfor  
NoRidge  
14260  
5
rows × 81 columns  
In [46]:  
import scipy.stats as stats  
def anova(training_data, qualitative):  
anv = pd.DataFrame()  
anv['feature'] = qualitative  
pvals = []  
for c in qualitative:  
samples = []  
for cls in training_data[c].unique():  
s = training_data[training_data[c] == cls]['SalePrice'].values  
samples.append(s)  
pval = stats.f_oneway(*samples)[1]  
pvals.append(pval)  
anv['pval'] = pvals  
return anv.sort_values('pval')  
a = anova(train_copy, cat_cols_update)  
a['disparity'] = np.log(1./a['pval'].values)  
print(a)  
feature  
pval  
disparity  
Neighborhood 2.151365e-225 517.315543  
ExterQual 5.868253e-212 486.378483  
BsmtQual 3.359597e-199 457.002613  
KitchenQual 3.691658e-197 452.303188  
GarageFinish 9.964625e-115 262.498244  
FireplaceQu 1.336345e-106 243.784082  
9
1
2
3
3
3
2
3
0
2
2
1
2
4
1
1
4
1
1
3
3
4
2
3
3
1
2
4
1
9
2
1
5
3
1
4
Foundation  
GarageType  
MSSubClass  
BsmtFinType1  
HeatingQC  
MasVnrType  
BsmtExposure  
SaleCondition  
Exterior1st  
Exterior2nd  
SaleType  
8.391803e-93 212.013158  
9.398860e-87 198.084315  
4.661331e-80 182.667506  
1.704168e-72 165.253050  
2.548399e-68 155.640321  
1.412167e-65 149.322905  
5.051140e-49 111.207056  
6.706183e-45 101.713299  
8.498134e-44  
2.096780e-43  
3.439409e-43  
1.391262e-34  
5.928185e-26  
7.157031e-25  
7.762692e-25  
3.539796e-24  
2.299502e-22  
2.154505e-18  
2.344710e-18  
6.251540e-17  
9.016654e-16  
1.313365e-10  
1.326059e-10  
5
8
8
4
5
6
7
4
99.173898  
98.270756  
97.775859  
77.957682  
58.087494  
55.596532  
55.515298  
53.997973  
49.824180  
40.678971  
40.594370  
37.311119  
34.642288  
22.753258  
22.743639  
MSZoning  
3
6
7
HouseStyle  
GarageQual  
GarageCond  
LotShape  
CentralAir  
Electrical  
PavedDrive  
RoofStyle  
BsmtCond  
9
0
8
4
3
0
2
Fence  
BldgType  
1
2
5
1
3
2
3
7
2
3
1
4
2
8
4
6
4
5
6
RoofMatl  
BsmtFinType2  
LandContour  
Condition1  
Alley  
2.311197e-08  
2.356121e-08  
8.562928e-08  
1.227638e-07  
3.402389e-07  
5.925523e-07  
6.095155e-07  
4.283725e-06  
4.279670e-04  
5.406450e-04  
1.354969e-02  
1.691842e-02  
4.749178e-02  
2.840375e-01  
4.694076e-01  
5.866737e-01  
6.197179e-01  
17.582915  
17.563664  
16.273239  
15.913004  
14.893618  
14.338827  
14.310601  
12.360688  
7.756465  
7.522748  
4.301392  
4.079352  
3.047199  
1.258649  
0.756284  
0.533286  
0.478491  
0
0
9
ExterCond  
PoolQC  
LotConfig  
Heating  
7
2
1
1
Functional  
Condition2  
MiscFeature  
Street  
LandSlope  
MoSold  
Utilities  
YrSold  
2
3
In [45]:  
plt.figure(figsize = (25, 8))  
sns.barplot(data=a, x='feature', y='disparity')  
x=plt.xticks(rotation=90)  
In [47]:  
In [48]:  
train_copy2 = train_copy.copy()  
#
#
#
Now encode qualitative variables according to ordering based on mean of SalePrice  
PCA and clustering  
Reference: https://www.kaggle.com/dgawlik/house-prices-eda  
def encode(training_data, feature):  
ordering = pd.DataFrame()  
ordering['val'] = training_data[feature].unique()  
ordering.index = ordering.val  
ordering['spmean'] = training_data[[feature, 'SalePrice']].groupby(feature).mean()['SalePrice']  
ordering = ordering.sort_values('spmean')  
ordering['ordering'] = range(1, ordering.shape[0]+1)  
ordering = ordering['ordering'].to_dict()  
for cat, o in ordering.items():  
training_data.loc[training_data[feature] == cat, feature+'_E'] = o  
qual_encoded = []  
for q in cat_cols_update:  
encode(train_copy2, q)  
qual_encoded.append(q+'_E')  
print(qual_encoded)  
[
'MSSubClass_E', 'MSZoning_E', 'Street_E', 'Alley_E', 'LotShape_E', 'LandContour_E', 'Utilities_E', 'LotConfig_E', 'LandSlope_E', 'N  
eighborhood_E', 'Condition1_E', 'Condition2_E', 'BldgType_E', 'HouseStyle_E', 'RoofStyle_E', 'RoofMatl_E', 'Exterior1st_E', 'Exterio  
r2nd_E', 'MasVnrType_E', 'ExterQual_E', 'ExterCond_E', 'Foundation_E', 'BsmtQual_E', 'BsmtCond_E', 'BsmtExposure_E', 'BsmtFinType1_  
E', 'BsmtFinType2_E', 'Heating_E', 'HeatingQC_E', 'CentralAir_E', 'Electrical_E', 'KitchenQual_E', 'Functional_E', 'FireplaceQu_E',  
'
GarageType_E', 'GarageFinish_E', 'GarageQual_E', 'GarageCond_E', 'PavedDrive_E', 'PoolQC_E', 'Fence_E', 'MiscFeature_E', 'MoSold_  
E', 'YrSold_E', 'SaleType_E', 'SaleCondition_E']  
In [49]:  
Out[49]:  
train_copy2.head()  
SalePrice Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig LandSlope Neighborhood Con  
0
1
2
3
4
208500  
181500  
223500  
140000  
250000  
1
2
3
4
5
60  
20  
60  
70  
60  
RL  
RL  
RL  
RL  
RL  
65.0  
80.0  
68.0  
60.0  
84.0  
8450  
9600  
Pave None  
Pave None  
Pave None  
Pave None  
Pave None  
Reg  
Reg  
IR1  
IR1  
IR1  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
AllPub  
AllPub  
AllPub  
AllPub  
AllPub  
Inside  
FR2  
Gtl  
Gtl  
Gtl  
Gtl  
Gtl  
CollgCr  
Veenker  
CollgCr  
11250  
9550  
Inside  
Corner  
FR2  
Crawfor  
NoRidge  
14260  
5
rows × 127 columns  
In [50]:  
num_cols_list = num_cols_update.to_list()  
len(num_cols_list)  
3
4
Out[50]:  
In [51]:  
len(qual_encoded)  
4
6
Out[51]:  
In [52]:  
all_features_num = num_cols_list + qual_encoded  
len(all_features_num)  
8
0
Out[52]:  
In [53]:  
print(all_features_num)  
[
2
'Id', 'LotFrontage', 'LotArea', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd', 'MasVnrArea', 'BsmtFinSF1', 'BsmtFinSF  
', 'BsmtUnfSF', 'TotalBsmtSF', '1stFlrSF', '2ndFlrSF', 'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath', 'Ha  
lfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'TotRmsAbvGrd', 'Fireplaces', 'GarageYrBlt', 'GarageCars', 'GarageArea', 'WoodDeckSF', 'Ope  
nPorchSF', 'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'MiscVal', 'MSSubClass_E', 'MSZoning_E', 'Street_E', 'Alley_E',  
'
LotShape_E', 'LandContour_E', 'Utilities_E', 'LotConfig_E', 'LandSlope_E', 'Neighborhood_E', 'Condition1_E', 'Condition2_E', 'BldgT  
ype_E', 'HouseStyle_E', 'RoofStyle_E', 'RoofMatl_E', 'Exterior1st_E', 'Exterior2nd_E', 'MasVnrType_E', 'ExterQual_E', 'ExterCond_E',  
Foundation_E', 'BsmtQual_E', 'BsmtCond_E', 'BsmtExposure_E', 'BsmtFinType1_E', 'BsmtFinType2_E', 'Heating_E', 'HeatingQC_E', 'Centr  
'
alAir_E', 'Electrical_E', 'KitchenQual_E', 'Functional_E', 'FireplaceQu_E', 'GarageType_E', 'GarageFinish_E', 'GarageQual_E', 'Garag  
eCond_E', 'PavedDrive_E', 'PoolQC_E', 'Fence_E', 'MiscFeature_E', 'MoSold_E', 'YrSold_E', 'SaleType_E', 'SaleCondition_E']  
In [54]:  
Out[54]:  
train_copy2 = train_copy2[all_features_num]  
train_copy2.head()  
Id LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
0
1
1
2
65.0  
80.0  
8450  
9600  
7
6
5
8
2003  
1976  
2003  
1976  
196.0  
0.0  
706.0  
978.0  
0.0  
0.0  
150.0  
284.0  
856.0  
856  
1262.0  
1262  
Id LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
2
3
4
3
4
5
68.0  
60.0  
84.0  
11250  
9550  
7
7
8
5
5
5
2001  
1915  
2000  
2002  
1970  
2000  
162.0  
0.0  
486.0  
216.0  
655.0  
0.0  
0.0  
0.0  
434.0  
540.0  
490.0  
920.0  
756.0  
920  
961  
14260  
350.0  
1145.0  
1145  
In [55]:  
Out[55]:  
train_copy2 = train_copy2.drop(['Id'],axis=1)  
train_copy2.shape  
(
1454, 79)  
Réduction des dimensions  
In [57]:  
#
it will take 15 sec  
from sklearn.manifold import TSNE  
from sklearn.cluster import KMeans  
from sklearn.decomposition import PCA  
from sklearn.preprocessing import StandardScaler  
#
#
sklearn.decomposition  
https://scikit-learn.org/stable/modules/classes.html#module-sklearn.decomposition  
#
#
sklearn.manifold  
https://scikit-learn.org/stable/modules/classes.html#module-sklearn.manifold  
#
#
sklearn.cluster  
https://scikit-learn.org/stable/modules/clustering.html  
#
modification: do PCA first, then TSNE and KMeans.  
std = StandardScaler()  
s = std.fit_transform(train_copy2)  
pca = PCA(n_components=30)  
pca.fit(s)  
pc = pca.transform(s)  
model = TSNE(n_components=2, random_state=0, perplexity=50)  
tsne = model.fit_transform(pc)  
kmeans = KMeans(n_clusters=5)  
kmeans.fit(tsne)  
fr = pd.DataFrame({'tsne1': tsne[:,0], 'tsne2': tsne[:, 1], 'cluster': kmeans.labels_})  
sns.lmplot(data=fr, x='tsne1', y='tsne2', hue='cluster', fit_reg=False)  
print(np.sum(pca.explained_variance_ratio_))  
0
.7471018056108714  
#
number of top correlated variables to price  
k = 25  
corrmat = train_copy.corr()  
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index  
cm = np.corrcoef(train_copy[cols].values.T)  
plt.subplots(figsize=(15, 15))  
sns.set(font_scale=1.25)  
sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.val  
plt.show()  
In [61]:  
#
drop useless columns, Id, Street, LandSlope, MoSold, Utilities, YrSold  
clean_data = all_data.copy()  
In [62]:  
Out[62]:  
clean_data = clean_data.drop(['Id', 'Street', 'LandSlope', 'MoSold', 'Utilities', 'YrSold'], axis=1)  
clean_data.shape, all_data.shape  
(
(2913, 74), (2913, 80))  
Pré-traitement des données  
Feature Engineering  
In [64]:  
num_cols_update = clean_data.columns[ clean_data.dtypes != 'object']  
num_cols_update.shape  
(
33,)  
Out[64]:  
In [65]:  
skewed_features = clean_data[num_cols_update].apply(lambda x: skew(x)).sort_values(ascending=False)  
high_skew = skewed_features[skewed_features > 0.5]  
skew_index = high_skew.index  
skew_index  
Index(['MiscVal', 'PoolArea', 'LowQualFinSF', '3SsnPorch', 'LotArea',  
Out[65]:  
'
'
'
'
'
KitchenAbvGr', 'BsmtFinSF2', 'EnclosedPorch', 'ScreenPorch',  
BsmtHalfBath', 'MasVnrArea', 'OpenPorchSF', 'WoodDeckSF', '1stFlrSF',  
GrLivArea', 'BsmtFinSF1', 'BsmtUnfSF', '2ndFlrSF', 'TotRmsAbvGrd',  
Fireplaces', 'HalfBath', 'TotalBsmtSF', 'LotFrontage', 'BsmtFullBath',  
OverallCond'],  
dtype='object')  
In [66]:  
Out[66]:  
high_skew  
MiscVal  
PoolArea  
LowQualFinSF  
21.947774  
17.676417  
12.076090  
11.364106  
5.292236  
4.297140  
4.159265  
3
SsnPorch  
LotArea  
KitchenAbvGr  
BsmtFinSF2  
EnclosedPorch  
ScreenPorch  
BsmtHalfBath  
MasVnrArea  
OpenPorchSF  
WoodDeckSF  
3.999248  
3.941914  
3.941288  
2.624563  
2.529118  
1.835030  
1.262143  
1.072962  
0.983610  
0.918984  
0.860895  
0.751795  
0.726878  
0.694488  
0.672301  
0.627404  
0.615937  
0.571107  
1
stFlrSF  
GrLivArea  
BsmtFinSF1  
BsmtUnfSF  
2
ndFlrSF  
TotRmsAbvGrd  
Fireplaces  
HalfBath  
TotalBsmtSF  
LotFrontage  
BsmtFullBath  
OverallCond  
dtype: float64  
In [67]:  
Out[67]:  
#
Normalize skewed features using log1p (log1p instead of log to avoid log0)  
for i in skew_index:  
clean_data[i] = np.log1p(clean_data[i])  
clean_data  
MSSubClass MSZoning LotFrontage LotArea Alley LotShape LandContour LotConfig Neighborhood Condition1 Condition2 BldgType HouseS  
0
1
2
3
4
60  
20  
60  
70  
60  
...  
RL  
RL  
RL  
RL  
RL  
...  
4.189655 9.042040 None  
4.394449 9.169623 None  
4.234107 9.328212 None  
4.110874 9.164401 None  
4.442651 9.565284 None  
Reg  
Reg  
IR1  
IR1  
IR1  
...  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
...  
Inside  
FR2  
CollgCr  
Veenker  
CollgCr  
Crawfor  
NoRidge  
...  
Norm  
Feedr  
Norm  
Norm  
Norm  
...  
Norm  
Norm  
Norm  
Norm  
Norm  
...  
1Fam  
1Fam  
1Fam  
1Fam  
1Fam  
...  
2S  
1S  
2S  
2S  
2S  
Inside  
Corner  
FR2  
.
..  
...  
...  
...  
...  
MSSubClass MSZoning LotFrontage LotArea Alley LotShape LandContour LotConfig Neighborhood Condition1 Condition2 BldgType HouseS  
2
2
2
2
2
908  
909  
910  
911  
912  
160  
160  
20  
RM  
RM  
RL  
3.091042 7.568896 None  
3.091042 7.546974 None  
5.081404 9.903538 None  
4.143135 9.253591 None  
4.317488 9.172431 None  
Reg  
Reg  
Reg  
Reg  
Reg  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
Inside  
Inside  
Inside  
Inside  
Inside  
MeadowV  
MeadowV  
Mitchel  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Twnhs  
TwnhsE  
1Fam  
2S  
2S  
1S  
SF  
2S  
85  
RL  
Mitchel  
1Fam  
60  
RL  
Mitchel  
1Fam  
2
913 rows × 74 columns  
In [68]:  
Out[68]:  
#
do the log1p transformation to the sale price too  
y_train_log1p = y_train.copy()  
y_train_log1p = np.log1p(y_train_log1p )  
y_train_log1p  
0
1
2
3
4
12.247699  
12.109016  
12.317171  
11.849405  
12.429220  
.
..  
1
1
1
1
1
449  
450  
451  
452  
453  
12.072547  
12.254868  
12.493133  
11.864469  
11.901590  
Name: SalePrice, Length: 1454, dtype: float64  
In [69]:  
#
add total square feet  
clean_data['TotalSF'] = clean_data['TotalBsmtSF'] + clean_data['1stFlrSF'] + clean_data['2ndFlrSF']  
clean_data.head()  
Out[69]:  
MSSubClass MSZoning LotFrontage LotArea Alley LotShape LandContour LotConfig Neighborhood Condition1 Condition2 BldgType HouseStyle  
0
1
2
3
4
60  
20  
60  
70  
60  
RL  
RL  
RL  
RL  
RL  
4.189655 9.042040 None  
4.394449 9.169623 None  
4.234107 9.328212 None  
4.110874 9.164401 None  
4.442651 9.565284 None  
Reg  
Reg  
IR1  
IR1  
IR1  
Lvl  
Lvl  
Lvl  
Lvl  
Lvl  
Inside  
FR2  
CollgCr  
Veenker  
CollgCr  
Norm  
Feedr  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
Norm  
1Fam  
1Fam  
1Fam  
1Fam  
1Fam  
2Story  
1Story  
2Story  
2Story  
2Story  
Inside  
Corner  
FR2  
Crawfor  
NoRidge  
In [70]:  
In [71]:  
#
add isOld label  
clean_data['isOldHouse'] = [1 if x < 1990 else 0 for x in clean_data['YearBuilt']]  
clean_data['isOldHouse'] = clean_data['isOldHouse'].apply(str)  
#
#
add isRemodel label  
YearRemodAdd: Remodel date (same as construction date if no remodeling or additions)  
diff_year = clean_data['YearRemodAdd'] - clean_data['YearBuilt']  
clean_data['isRemodel'] = [1 if x != 0 else 0 for x in diff_year]  
In [72]:  
Out[72]:  
clean_data['isRemodel'] = clean_data['isRemodel'].apply(str)  
clean_data.head()  
MSSubClass MSZoning LotFrontage LotArea Alley LotShape LandContour LotConfig Neighborhood Condition1 Condition2 BldgType HouseStyle  
0
1
2
60  
20  
60  
RL  
RL  
RL  
4.189655 9.042040 None  
4.394449 9.169623 None  
4.234107 9.328212 None  
Reg  
Reg  
IR1  
Lvl  
Lvl  
Lvl  
Inside  
FR2  
CollgCr  
Veenker  
CollgCr  
Norm  
Feedr  
Norm  
Norm  
Norm  
Norm  
1Fam  
1Fam  
1Fam  
2Story  
1Story  
2Story  
Inside  
MSSubClass MSZoning LotFrontage LotArea Alley LotShape LandContour LotConfig Neighborhood Condition1 Condition2 BldgType HouseStyle  
3
4
70  
60  
RL  
RL  
4.110874 9.164401 None  
4.442651 9.565284 None  
IR1  
IR1  
Lvl  
Lvl  
Corner  
FR2  
Crawfor  
Norm  
Norm  
Norm  
Norm  
1Fam  
1Fam  
2Story  
2Story  
NoRidge  
In [73]:  
clean_data['hasPool'] = clean_data['PoolArea'].apply(lambda x: 1 if x > 0 else 0)  
clean_data['hasPool'] = clean_data['hasPool'].apply(str)  
clean_data['has2ndfloor'] = clean_data['2ndFlrSF'].apply(lambda x: 1 if x > 0 else 0)  
clean_data['has2ndfloor'] = clean_data['has2ndfloor'].apply(str)  
clean_data['hasGarage'] = clean_data['GarageArea'].apply(lambda x: 1 if x > 0 else 0)  
clean_data['hasGarage'] = clean_data['hasGarage'].apply(str)  
clean_data['hasBasement'] = clean_data['TotalBsmtSF'].apply(lambda x: 1 if x > 0 else 0)  
clean_data['hasBasement'] = clean_data['hasBasement'].apply(str)  
In [177…  
Out[177…  
clean_data  
LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
0
1
2
3
4
4.189655 9.042040  
4.394449 9.169623  
4.234107 9.328212  
4.110874 9.164401  
4.442651 9.565284  
7
6
7
7
8
...  
1.791759  
2.197225  
1.791759  
1.791759  
1.791759  
...  
2003  
1976  
2001  
1915  
2000  
...  
2003  
1976  
2002  
1970  
2000  
...  
5.283204  
0.000000  
5.093750  
0.000000  
5.860786  
...  
6.561031  
6.886532  
6.188264  
5.379897  
6.486161  
...  
0.0  
0.0  
0.0  
0.0  
0.0  
...  
5.017280  
5.652489  
6.075346  
6.293419  
6.196444  
...  
6.753438 6.753438  
7.141245 7.141245  
6.825460 6.825460  
6.629363 6.869014  
7.044033 7.044033  
.
..  
...  
...  
...  
..  
LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
2
2
2
2
2
908  
909  
910  
911  
912  
3.091042 7.568896  
3.091042 7.546974  
5.081404 9.903538  
4.143135 9.253591  
4.317488 9.172431  
4
4
5
5
7
2.079442  
1.791759  
2.079442  
1.791759  
1.791759  
1970  
1970  
1960  
1992  
1993  
1970  
1970  
1996  
1992  
1994  
0.000000  
0.000000  
0.000000  
0.000000  
4.553877  
0.000000  
5.533389  
7.110696  
5.823046  
6.632002  
0.0  
0.0  
0.0  
0.0  
0.0  
6.304449  
5.686975  
0.000000  
6.356108  
5.476464  
6.304449 6.304449  
6.304449 6.304449  
7.110696 7.110696  
6.816736 6.878326  
6.904751 6.904751  
2
913 rows × 320 columns  
In [178…  
#
Creating dummy variables to convert categorical features into numerical features  
clean_data = pd.get_dummies(clean_data)  
clean_data.shape  
(
2913, 320)  
Out[178…  
In [179…  
#
Split training data and test data  
id_train = y_train.shape[0]  
X_train1 = clean_data[:id_train]  
X_test1 = clean_data[id_train:]  
In [180…  
Out[180…  
X_train1.shape, X_test1.shape, y_train_log1p.shape  
(
(1454, 320), (1459, 320), (1454,))  
Training models  
Metric: Submissions are evaluated on Root-Mean-Squared-Error (RMSE) between the logarithm of the predicted value and the logarithm of the  
observed sales price. (Taking logs means that errors in predicting expensive houses and cheap houses will affect the result equally.)  
In [181…  
from sklearn.model_selection import cross_val_score, GridSearchCV, KFold  
from sklearn.linear_model import Ridge, Lasso, BayesianRidge  
from sklearn.tree import DecisionTreeRegressor  
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, ExtraTreesRegressor  
from sklearn.svm import SVR  
from lightgbm import LGBMRegressor  
from xgboost import XGBRegressor  
In [182…  
In [183…  
#
Setup cross validation folds  
kfold = KFold(n_splits=10, random_state=42, shuffle=True)  
#
define error evaluation metrics  
def rmse(model, features, label, kf):  
rmse = np.sqrt(-cross_val_score(model, features, label, scoring="neg_mean_squared_error", cv=kf))  
return rmse  
In [184…  
In [185…  
from sklearn.pipeline import Pipeline, make_pipeline  
Training models without any parametre  
models = [Ridge(),  
Lasso(),  
BayesianRidge(),  
DecisionTreeRegressor(),  
RandomForestRegressor(),  
GradientBoostingRegressor(),  
ExtraTreesRegressor(),  
SVR(),  
LGBMRegressor(),  
XGBRegressor(objective="reg:squarederror")]  
In [186…  
In [187…  
scores_without_para = {}  
#
it will take 1m 39s  
names = ["Ridge", "Lasso", "BayesianRidge", "DecisionTree", "RandomForest", "GradientBoosting", "ExtraTrees", "SVR", "LGBM", "XGB"]  
for name, model in zip(names, models):  
score = rmse(model, X_train1, y_train_log1p, kfold)  
print("{}: {:.6f}, {:.4f}".format(name, score.mean(), score.std()))  
scores_without_para[name] = (score.mean(), score.std())  
Ridge: 0.113670, 0.0156  
Lasso: 0.264437, 0.0165  
BayesianRidge: 0.111524, 0.0146  
DecisionTree: 0.203293, 0.0208  
RandomForest: 0.138647, 0.0112  
GradientBoosting: 0.124211, 0.0132  
ExtraTrees: 0.135837, 0.0117  
SVR: 0.278071, 0.0189  
LGBM: 0.127936, 0.0106  
XGB: 0.123820, 0.0137  
In [188…  
Out[188…  
scores_without_para  
{
'BayesianRidge': (0.11152364174516809, 0.014610105764083678),  
'
'
'
'
'
'
'
DecisionTree': (0.20329332091078395, 0.020813804969743218),  
ExtraTrees': (0.13583698815974407, 0.011687558848375582),  
GradientBoosting': (0.12421079266874475, 0.013232199156665075),  
LGBM': (0.12793595771153096, 0.010562894678581519),  
Lasso': (0.2644367647702661, 0.016512062154763644),  
RandomForest': (0.13864741801054345, 0.011193157376533924),  
Ridge': (0.11367022793177506, 0.015625304438968507),  
'
'
SVR': (0.27807107770362643, 0.01888625887475614),  
XGB': (0.12382025563798364, 0.013715297371762254)}  
Using gridsearch method for the hyperparameters tuning  
In [189…  
In [190…  
scores_with_para = {}  
class grid_search():  
def __init__(self, model):  
self.model = model  
def opt(self, X, y, param_grid, kf):  
model_search = GridSearchCV(self.model, param_grid, cv=kf, scoring="neg_mean_squared_error")  
model_search.fit(X,y)  
print(model_search.best_params_, np.sqrt(-model_search.best_score_))  
In [191…  
#
#
#
#
#
#
hyperparameter tuning for svr  
https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html  
Parameter reference:  
https://www.kaggle.com/lavanyashukla01/how-i-made-top-0-3-on-a-kaggle-competition  
https://www.kaggle.com/massquantity/all-you-need-is-pca-lb-0-11421-top-4  
it will take 50 sec  
param_grid_svr = {'C':[12, 15, 20], "gamma":[0.0003], "epsilon":[0.008]}  
grid_search(SVR()).opt(X_train1, y_train_log1p, param_grid_svr, kfold)  
{
'C': 12, 'epsilon': 0.008, 'gamma': 0.0003} 0.18317707784189322  
In [192…  
#
#
Apply RobustScaler to the traning data  
it wil take 9 sec  
from sklearn.preprocessing import RobustScaler  
svr_robust_scalar = make_pipeline(RobustScaler(), SVR(C = 12, epsilon = 0.008, gamma = 0.0003))  
score_svr_robusts_scaler = rmse(svr_robust_scalar, X_train1, y_train_log1p, kfold)  
print("SVR_robusts_scaler: {:.4f} ({:.4f})".format(score_svr_robusts_scaler.mean(), score_svr_robusts_scaler.std()))  
scores_with_para['SVR_robusts_scaler'] = (score_svr_robusts_scaler.mean(), score_svr_robusts_scaler.std())  
SVR_robusts_scaler: 0.1100 (0.0143)  
the first result (0.27807)  
the result after hyperparameter tuning (0.183177),  
we obtain 0.11 as result after applying RobustScaler()  
In [193…  
#
#
#
Hyperpamameter tuning for Decision tree regressor  
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html  
it will take 21 sec  
param_grid_decisiontree = {"max_depth": [3, 4, 5, 8, 10], "min_samples_split" : [5, 6, 7, 8], "min_samples_leaf" : [5, 6, 7, 8]}  
grid_search(DecisionTreeRegressor()).opt(X_train1, y_train_log1p, param_grid_decisiontree, kfold)  
{
'max_depth': 8, 'min_samples_leaf': 7, 'min_samples_split': 5} 0.18077214522827295  
There is almost no improvement for the decision tree regressor even though we use the hyperparameter tuning.  
In [194…  
#
#
Hyperpamameter tuning for XGBRegressor  
the training will take 2 min 29 sec  
xgb = XGBRegressor(gamma=0.05, learning_rate=0.05, max_depth=3, n_estimators=2000, objective="reg:squarederror")  
In [195… score_xgb_para = rmse(xgb, X_train1, y_train_log1p, kfold)  
print("xgboost: {:.4f} ({:.4f})".format(score_xgb_para.mean(), score_xgb_para.std()))  
scores_with_para['xgb_para_opt'] = (score_xgb_para.mean(), score_xgb_para.std())  
xgboost: 0.1227 (0.0135)  
In [196…  
#
the training will take 29 sec  
lightgbm_para = LGBMRegressor(objective='regression', num_leaves=6, learning_rate=0.05, n_estimators=7000,  
max_bin=200, random_state=42)  
In [197…  
score_lightgbm_para = rmse(lightgbm_para, X_train1, y_train_log1p, kfold)  
print("lightgbm: {:.4f} ({:.4f})".format(score_lightgbm_para.mean(), score_lightgbm_para.std()))  
scores_with_para['lightgbm_para'] = (score_lightgbm_para.mean(), score_lightgbm_para.std())  
lightgbm: 0.1251 (0.0117)  
scores_with_para  
In [198…  
Out[198…  
{
'SVR_robusts_scaler': (0.11004557443046728, 0.014283810164719747),  
'
'
lightgbm_para': (0.1251244358577163, 0.011736671168271097),  
xgb_para_opt': (0.12267646814042757, 0.01347317629207774)}  
In [199…  
Out[199…  
scores_without_para  
{
'BayesianRidge': (0.11152364174516809, 0.014610105764083678),  
'
'
'
'
'
'
'
'
'
DecisionTree': (0.20329332091078395, 0.020813804969743218),  
ExtraTrees': (0.13583698815974407, 0.011687558848375582),  
GradientBoosting': (0.12421079266874475, 0.013232199156665075),  
LGBM': (0.12793595771153096, 0.010562894678581519),  
Lasso': (0.2644367647702661, 0.016512062154763644),  
RandomForest': (0.13864741801054345, 0.011193157376533924),  
Ridge': (0.11367022793177506, 0.015625304438968507),  
SVR': (0.27807107770362643, 0.01888625887475614),  
XGB': (0.12382025563798364, 0.013715297371762254)}  
We will mix the following models to do the prediction:  
BayesianRidge without parameter  
ExtraTrees without parameter  
RandomForest without parameter  
GradientBoosting without parameter  
LGBM with parameter  
Ridge without parameter  
SVR with parameter and robusts_scaler  
XGBoost with parameter  
In [200…  
Ridge_model = Ridge().fit(X_train1, y_train_log1p)  
BayesianRidge_model = BayesianRidge().fit(X_train1, y_train_log1p)  
RandomForestRegressor_model = RandomForestRegressor().fit(X_train1, y_train_log1p)  
GradientBoostingRegressor_model = GradientBoostingRegressor().fit(X_train1, y_train_log1p)  
ExtraTreesRegressor_model = ExtraTreesRegressor().fit(X_train1, y_train_log1p)  
In [201…  
In [202…  
svr_robust_scalar = make_pipeline(RobustScaler(), SVR(C = 12, epsilon = 0.008, gamma = 0.0003))  
svr_robust_scalar_model = svr_robust_scalar.fit(X_train1, y_train_log1p)  
lightgbm_para = LGBMRegressor(objective='regression', num_leaves=6, learning_rate=0.05, n_estimators=7000,  
max_bin=200, random_state=42)  
lightgbm_para_model = lightgbm_para.fit(X_train1, y_train_log1p)  
xgb_para = XGBRegressor(gamma=0.05, learning_rate=0.05, max_depth=3, n_estimators=2000, objective="reg:squarederror")  
xgb_para_model = xgb_para.fit(X_train1, y_train_log1p)  
In [203…  
In [222…  
def mix_models_1(test_data):  
Ridge_pred = 0.25 * Ridge_model.predict(test_data)  
BayesianRidge_pred = 0.25 * BayesianRidge_model.predict(test_data)  
GradientBoosting_pred = 0.1 * GradientBoostingRegressor_model.predict(test_data)  
svr_pred = 0.2 * svr_robust_scalar_model.predict(test_data)  
lightgbm_pred = 0.1 * lightgbm_para_model.predict(test_data)  
xgb_pred = 0.1 * xgb_para_model.predict(test_data)  
return (Ridge_pred + BayesianRidge_pred + GradientBoosting_pred + svr_pred + lightgbm_pred + xgb_pred)  
In [223…  
def mix_models_2(test_data):  
Ridge_pred = 0.25 * Ridge_model.predict(test_data)  
BayesianRidge_pred = 0.25 * BayesianRidge_model.predict(test_data)  
ExtraTrees_pred = 0.05 * ExtraTreesRegressor_model.predict(test_data)  
GradientBoosting_pred = 0.1 * GradientBoostingRegressor_model.predict(test_data)  
svr_pred = 0.15 * svr_robust_scalar_model.predict(test_data)  
lightgbm_pred = 0.05 * lightgbm_para_model.predict(test_data)  
xgb_pred = 0.15 * xgb_para_model.predict(test_data)  
return (Ridge_pred + BayesianRidge_pred + GradientBoosting_pred + svr_pred + lightgbm_pred + xgb_pred + ExtraTrees_pred)  
In [224…  
In [225…  
from sklearn.metrics import mean_squared_error  
def rmse_test(y, y_pred):  
return np.sqrt(mean_squared_error(y, y_pred))  
#
Get final precitions from the blended model  
mixedmodel_score = rmse_test(y_train_log1p, mix_models_1(X_train1))  
mixedmodel_score  
0
.0786345468008342  
Out[225…  
In [226…  
mixedmodel_score = rmse_test(y_train_log1p, mix_models_2(X_train1))  
mixedmodel_score  
0
.07735650443054667  
Out[226…  
In [210…  
Prediction  
from google.colab import files  
upload_submission = files.upload()  
Choose Files No file chosen  
Upload widget is only available when the cell has been executed in the current browser session. Please rerun  
this cell to enable.  
Saving sample_submission.csv to sample_submission (1).csv  
In [211…  
import pandas as pd  
import io  
submission1 = pd.read_csv(io.BytesIO(upload_submission['sample_submission.csv']), index_col=None)  
submission1.shape  
(
1459, 2)  
Out[211…  
In [212…  
X_test1.head()  
Out[212…  
LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
1
1
454  
455  
4.394449 9.360741  
4.406719 9.565775  
5
6
1.945910  
1.945910  
1961  
1958  
1961  
1958  
0.000000  
4.691348  
6.150603  
6.828712  
4.976734  
0.000000  
5.602119  
6.008813  
6.783325 6.799056  
7.192934 7.192934  
LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 BsmtFinSF2 BsmtUnfSF TotalBsmtSF 1stFlrSF  
1
1
1
456  
457  
458  
4.317488 9.534668  
4.369448 9.208238  
3.784190 8.518392  
5
6
8
1.791759  
1.945910  
1.791759  
1997  
1998  
1992  
1998  
1998  
1992  
0.000000  
3.044522  
0.000000  
6.674561  
6.401917  
5.575949  
0.000000  
0.000000  
0.000000  
4.927254  
5.783825  
6.925595  
6.834109 6.834109  
6.831954 6.831954  
7.155396 7.155396  
5
rows × 320 columns  
In [227…  
submission1.iloc[:,1] = np.floor(np.expm1(mix_models_1(X_test1)))  
In [228…  
Out[228…  
submission1  
Id SalePrice  
0
1
2
3
4
1461 122685.0  
1462 157836.0  
1463 187645.0  
1464 198588.0  
1465 196973.0  
.
..  
...  
...  
83449.0  
80071.0  
1
454 2915  
455 2916  
1
1
1
456 2917 167041.0  
457 2918 120601.0  
Id SalePrice  
1
458 2919 218959.0  
1
459 rows × 2 columns  
In [229…  
submission2 = pd.read_csv(io.BytesIO(upload_submission['sample_submission.csv']), index_col=None)  
submission2.shape  
(
1459, 2)  
Out[229…  
In [230…  
submission2.iloc[:,1] = np.floor(np.expm1(mix_models_2(X_test1)))  
In [231…  
Out[231…  
submission2  
Id SalePrice  
0
1
2
3
4
1461 122587.0  
1462 157112.0  
1463 186799.0  
1464 197134.0  
1465 197405.0  
.
..  
...  
...  
83181.0  
80500.0  
1
454 2915  
455 2916  
1
1
456 2917 166556.0  
Id SalePrice  
457 2918 120535.0  
458 2919 219782.0  
1
1
1
459 rows × 2 columns  
In [232…  
In [233…  
from google.colab import files  
submission1.to_csv('submission1.csv', index=False)  
files.download('submission1.csv')  
from google.colab import files  
submission2.to_csv('submission2.csv', index=False)  
files.download('submission2.csv')  
public score for submission1 : 0.12255  
public score for submission2 : 0.12332